package com.clp.protocol.iec104.iec104.apdu.asdu;

import com.clp.protocol.core.nbytepdu.BaseNBytePduClip;
import com.clp.protocol.core.pdu.ByteToStringFormat;
import com.clp.protocol.iec104.iec104.definition.ConstVal;
import com.clp.protocol.iec104.iec104.definition.cot.Cause;
import com.clp.protocol.iec104.iec104.definition.cot.Pn;
import com.clp.protocol.iec104.iec104.definition.cot.Test;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.Objects;
import java.util.function.Consumer;

/**
 * 传输原因 2个字节
 */
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Cot extends BaseNBytePduClip<Cot> {
    /**
     * D7:试验为1，未试验为0
     */
    private Test test;
    /**
     * D6：否定确认为1，肯定确认为0
     */
    private Pn pn;
    /**
     * 传输原因
     */
    private Cause cause;

    @Override
    public Cot refreshFrom(ByteBuf buf) {
        byte[] bytes = new byte[ConstVal.COT_LEN];
        buf.readBytes(bytes);
        this.test = Test.gain((bytes[0] & 0x80) == 0x80 ? 1 : 0);
        this.pn = Pn.gain((bytes[0] & 0x40) == 0x40 ? 1 : 0);
        this.cause = Cause.gain(bytes[0] & 0x3F);
        return this;
    }

    @Override
    public boolean isValid() {
        return test != null && pn != null && cause != null;
    }

    @Override
    public void writeBytesTo(ByteBuf buf) {
        buf.writeBytes(generateBytes());
    }

    private byte[] generateBytes() {
        byte[] bytes = new byte[]{0x00, 0x00}; // 传输原因2字节，要补空位
        if (test.getVal() == 1) bytes[0] |= 0x80;
        if (pn.getVal() == 1) bytes[0] |= 0x40;
        bytes[0] |= cause.getVal();
        return bytes;
    }

    @Override
    public void writeFormattedByteStringsTo(StringBuilder sb, String frameClipBytesSeparator, String byteSeparator, ByteToStringFormat byteFormat) {
        byte[] bytes = generateBytes();
        sb.append(byteFormat.format(bytes[0]));
        for (int i = 1; i < bytes.length; i++) {
            sb.append(byteSeparator).append(byteFormat.format(bytes[i]));
        }
    }

    @Override
    public void writeSimpleDescriptionTo(StringBuilder sb) {
        sb.append("<").append(test.getDesc()).append("(").append(test.getVal()).append("), ")
                .append(pn.getDesc()).append("(").append(pn.getVal()).append("), ").append(cause.getDesc())
                .append("(").append(cause.getVal()).append(")>");
    }

    @Override
    public void writeDetailDescriptionTo(StringBuilder sb) {
        sb.append("<Test：").append(test.getDesc()).append("(").append(test.getVal()).append("), Pn：")
                .append(pn.getDesc()).append("(").append(pn.getVal()).append("), Cause：").append(cause.getDesc())
                .append("(").append(cause.getVal()).append(")>");
    }

    @Override
    protected void forEachOneLevelChild(Consumer<BaseNBytePduClip<?>> consumer) {

    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Cot cot = (Cot) o;
        return test == cot.test && pn == cot.pn && cause == cot.cause;
    }

    @Override
    public int hashCode() {
        return Objects.hash(test, pn, cause);
    }
}
